package com.castle.fortress.admin.flowable.service.impl;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.castle.fortress.admin.flowable.cmd.FortressInjectSingleUserTaskInProcessInstanceCmd;
import com.castle.fortress.admin.flowable.cmd.FortressInjectUserTaskInProcessInstanceCmd;
import com.castle.fortress.admin.flowable.dto.ApproveUserDto;
import com.castle.fortress.admin.flowable.dto.FlowableAppDto;
import com.castle.fortress.admin.flowable.dto.FlowableTemplateDto;
import com.castle.fortress.admin.flowable.dto.ProcessDto;
import com.castle.fortress.admin.flowable.entity.FlowableCommentExtendEntity;
import com.castle.fortress.admin.flowable.entity.FlowableTemplateEntity;
import com.castle.fortress.admin.flowable.enums.ApproveStatusEnum;
import com.castle.fortress.admin.flowable.form.service.FlowableFormDataService;
import com.castle.fortress.admin.flowable.service.FlowableAppService;
import com.castle.fortress.admin.flowable.service.FlowableCommentExtendService;
import com.castle.fortress.admin.flowable.service.FlowableManageService;
import com.castle.fortress.admin.flowable.service.FlowableTemplateService;
import com.castle.fortress.admin.flowable.utils.FlowableUtils;
import com.castle.fortress.admin.form.dto.FormDataDto;
import com.castle.fortress.admin.system.entity.SysRole;
import com.castle.fortress.admin.system.entity.SysUser;
import com.castle.fortress.admin.system.entity.SysUserRole;
import com.castle.fortress.admin.system.service.SysUserRoleService;
import com.castle.fortress.admin.system.service.SysUserService;
import com.castle.fortress.common.entity.RespBody;
import com.castle.fortress.common.enums.YesNoEnum;
import com.castle.fortress.common.exception.BizException;
import com.castle.fortress.common.respcode.BizErrorCode;
import com.castle.fortress.common.respcode.GlobalRespCode;
import com.castle.fortress.common.utils.CommonUtil;
import com.castle.fortress.common.utils.ConvertUtil;
import lombok.extern.log4j.Log4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.model.*;
import org.flowable.common.engine.api.delegate.Expression;
import org.flowable.common.engine.api.variable.VariableContainer;
import org.flowable.common.engine.impl.el.ExpressionManager;
import org.flowable.common.engine.impl.el.VariableContainerWrapper;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.history.HistoricProcessInstanceQuery;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.impl.dynamic.DynamicUserTaskBuilder;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.task.Comment;
import org.flowable.identitylink.api.history.HistoricIdentityLink;
import org.flowable.task.api.DelegationState;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 流程管理 服务实现类
 *
 * @author castle
 */
@Service
@Log4j
public class FlowableManageServiceImpl implements FlowableManageService {
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    @Qualifier("processEngine")
    private ProcessEngine processEngine;
    @Autowired
    private IdentityService identityService;
    @Autowired
    private FlowableTemplateService flowableTemplateService;
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private FlowableFormDataService flowableFormDataService;
    @Autowired
    private SysUserRoleService sysUserRoleService;
    @Autowired
    private DynamicBpmnService dynamicBpmnService;
    @Autowired
    private ManagementService managementService;
    @Autowired
    private FlowableCommentExtendService flowableCommentExtendService;
    @Autowired
    private FlowableAppService flowableAppService;


    @Override
    public RespBody<Map<String,String>> deploy(String actKey) {
        if(StrUtil.isEmpty(actKey)){
            throw new BizException(GlobalRespCode.PARAM_MISSED);
        }
        FlowableTemplateDto flowableTemplateDto = new FlowableTemplateDto();
        flowableTemplateDto.setActKey(actKey);
        List<FlowableTemplateDto> dtos = flowableTemplateService.listFlowableTemplate(flowableTemplateDto);
        if(dtos==null || dtos.size()!=1){
            throw new BizException(BizErrorCode.ACT_KEY_ERROR);
        }
        //TODO 校验状态
        Deployment deployment = repositoryService.createDeployment().addString(actKey+"-Request.bpmn20.xml",dtos.get(0).getContentXml()).name(dtos.get(0).getTitle()).key(actKey).category("castle")
                .deploy();
        ProcessDefinition pd = repositoryService.createProcessDefinitionQuery().processDefinitionKey(actKey).latestVersion().singleResult();
        System.out.println("部署ID:"+deployment.getId());
        System.out.println("部署Key:"+deployment.getKey());
        System.out.println("部署Name:"+deployment.getName());
                Map<String,String> result = new HashMap<>();
        result.put("id",deployment.getId());
        result.put("version",pd.getVersion()+"");
        return RespBody.data(result);
    }

    @Override
    public RespBody<String> runProcess(ProcessDto processDto,SysUser user) {
        identityService.setAuthenticatedUserId(user.getId()+"");
        processDto.getVariables().put("_castle_flowable_start_userid",user.getId());
        processDto.getVariables().put("_castle_flowable_begin_times",new Date());
        ProcessInstance processInstance = null;
        try {
            processInstance = runtimeService.startProcessInstanceByKey(processDto.getActKey(), processDto.getVariables());
            ProcessDefinition pd = repositoryService.createProcessDefinitionQuery().processDefinitionKey(processDto.getActKey()).latestVersion().singleResult();
            flowableFormDataService.updateProcessId(processDto.getVariables().get("tid").toString(),processDto.getVariables().get("id").toString(),processInstance.getProcessInstanceId(),pd.getVersion()+"");
            return RespBody.data("提交成功,流程ID为：" + processInstance.getId());
        } catch (Exception e) {
            e.printStackTrace();
            throw new BizException(BizErrorCode.FLOWABLE_CONFIG_ERROR);
        }

    }

    @Async
    @Override
    public RespBody<String> runProcess(Long tbId, Map<String,Object> formData,SysUser user) {
//        FlowableTemplateDto flowableTemplateDto = new FlowableTemplateDto();
//        flowableTemplateDto.setFormKey(tbId);
//        flowableTemplateDto.setStatus(YesNoEnum.YES.getCode());
//        List<FlowableTemplateDto> templates =  flowableTemplateService.listFlowableTemplate(flowableTemplateDto);
//        if(templates==null || templates.size()!= 1){
//            throw new BizException(BizErrorCode.FLOWABLE_CONFIG_ERROR);
//        }
//        FlowableTemplateDto dto = templates.get(0);
        ProcessDto processDto = new ProcessDto();
        processDto.setActKey(CommonUtil.emptyIfNull(formData.get("_castle_flowable_ack_key")));
        processDto.setVariables(formData);
        return runProcess(processDto,user);
    }

    @Override
    public IPage<Map<String, Object>> myTasks(Page<FlowableTemplateDto> page, SysUser user,Map<String,String> params) {
        List<Map<String,Object>> list = new ArrayList<>();
        HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery().includeProcessVariables();
        //非超管只能查看自己的
        if(!user.getIsAdmin()&&!user.getIsSuperAdmin()){
            query.startedBy(user.getId()+"");
        }
        query.orderByProcessInstanceStartTime().desc();
        long total = query.count();
        Page<Map<String, Object>> pageDto = new Page(page.getCurrent(), page.getSize(),total);
        Map<String,Integer> pageMap = getPageParam(page,(int)pageDto.getTotal());
        List<HistoricProcessInstance> processInstance = query.listPage(pageMap.get("start"),pageMap.get("end"));
        for(HistoricProcessInstance p:processInstance){
            Map<String,Object> m = new HashMap<>();
            m.put("processId",p.getId());
            m.put("deployId",p.getDeploymentId());
            m.put("appName",p.getProcessVariables().get("_castle_flowable_app_title"));
            m.put("actKey",p.getProcessDefinitionKey());
            m.put("createTime", DateUtil.formatDateTime(p.getStartTime()));
//            Map<String, Object> oldData = flowableFormDataService.queryById(p.getProcessVariables().get("tid").toString(),p.getProcessVariables().get("id").toString());
            Map<String, Object> oldData = p.getProcessVariables().containsKey("_fortress_form_data_map")?((Map<String, Object>)p.getProcessVariables().get("_fortress_form_data_map")):new HashMap<>();;
            m.put("status",oldData.get("_castle_approve_status"));
            m.put("dataId",p.getProcessVariables().get("id"));
            m.put("tid",p.getProcessVariables().get("tid"));
            m.put("_castle_process_engine_version",oldData.get("_castle_process_engine_version"));
            list.add(m);
        }
        pageDto.setRecords(list);
        return pageDto;
    }

    @Override
    public IPage<Map<String, Object>> todoTasks(Page<FlowableTemplateDto> page, SysUser user, Map<String, String> params) {
        TaskQuery query = taskService.createTaskQuery();
        //非超管只能查看自己的
        if(!user.getIsAdmin()&&!user.getIsSuperAdmin()){
            List<String> roles = new ArrayList<>();
            for(SysRole r:user.getRoles()){
                roles.add(r.getId()+"");
            }
            query.or().taskAssignee(user.getId()+"").taskCandidateUser(user.getId()+"").taskCandidateGroupIn(roles).endOr();
        }
        if(params!=null){
            if(StrUtil.isNotEmpty(params.get("appName"))){
                query.processDefinitionNameLike(params.get("appName"));
            }
            if(StrUtil.isNotEmpty(params.get("startTime"))){
                Date d =DateUtil.parseDate(params.get("startTime"));
                query.taskCreatedAfter(d);
            }
            if(StrUtil.isNotEmpty(params.get("endTime"))){
                query.taskCreatedBefore(DateUtil.parseDate(params.get("endTime")));
            }
        }
        query.includeProcessVariables().orderByTaskCreateTime().desc();
        long total = query.count();
        Page<Map<String, Object>> pageDto = new Page(page.getCurrent(), page.getSize(),total);
        Map<String,Integer> pageMap = getPageParam(page,(int)pageDto.getTotal());
        List<Task> tasks = query.listPage(pageMap.get("start"),pageMap.get("end"));

//        List<Task> tasksAll =query.includeProcessVariables().orderByTaskCreateTime().desc().list();
//        Page<Map<String, Object>> pageDto = new Page(page.getCurrent(), page.getSize(),tasksAll.size());
//        Map<String,Integer> pageMap = getPageParam(page,tasksAll.size());
//        List<Task> tasks = tasksAll.subList(pageMap.get("start"),pageMap.get("end"));
        List<Map<String,Object>> list = new ArrayList<>();
        for (Task t : tasks) {
            Map<String,Object> m = new HashMap<>();
//            ProcessInstance p =runtimeService.createProcessInstanceQuery().processInstanceId(t.getProcessInstanceId()).singleResult();
            m.put("taskId",t.getId());
//            m.put("processId",p.getId());
//            m.put("deployId",p.getDeploymentId());
//            m.put("appName",p.getProcessDefinitionName());
//            m.put("actKey",p.getProcessDefinitionKey());

            m.put("processId",t.getProcessInstanceId());
//            m.put("deployId",p.getDeploymentId());
            m.put("appName",t.getProcessVariables().get("_castle_flowable_app_title"));
            m.put("actKey",t.getProcessVariables().get("_castle_flowable_ack_key"));

            m.put("createTime",DateUtil.formatDateTime(t.getCreateTime()));

            //申请人信息
//            if(StrUtil.isNotEmpty(p.getStartUserId()) && !"-1".equals(p.getStartUserId())){
//                SysUser applyUser = sysUserService.getByIdExtends(Long.parseLong(p.getStartUserId()));
//                m.put("applyUserName",applyUser.getLoginName());
//                m.put("deptName",applyUser.getDeptName());
//            }
//            m.put("applyUserId",p.getStartUserId());
//            m.put("applyTime",DateUtil.formatDateTime(p.getStartTime()));

            String startUserId = CommonUtil.emptyIfNull(t.getProcessVariables().get("_castle_flowable_start_userid"));
            if(StrUtil.isNotEmpty(startUserId) && !"-1".equals(startUserId)){
                SysUser applyUser = sysUserService.getByIdExtends(Long.parseLong(startUserId));
                if (applyUser == null){
                    m.put("applyUserName","");
                    m.put("deptName","");
                }else {
                    m.put("applyUserName",applyUser.getLoginName());
                    m.put("deptName",applyUser.getDeptName());
                }
            }
            m.put("applyUserId",startUserId);
            m.put("applyTime",DateUtil.formatDateTime((Date)t.getProcessVariables().get("_castle_flowable_begin_times")));

            //申请数据
            m.put("dataId",t.getProcessVariables().get("id"));
            m.put("tid",t.getProcessVariables().get("tid"));
//            Map<String, Object> oldData = flowableFormDataService.queryById(m.get("tid").toString(),m.get("dataId").toString());
            Map<String, Object> oldData = t.getProcessVariables().containsKey("_fortress_form_data_map")?((Map<String, Object>)t.getProcessVariables().get("_fortress_form_data_map")):new HashMap<>();;
            m.put("_castle_process_engine_version",oldData.get("_castle_process_engine_version"));
            list.add(m);
        }
        pageDto.setRecords(list);
        return pageDto;
    }

    @Override
    public String completeTask(SysUser user, Map<String, String> params) {
        if(params==null || CommonUtil.verifyParamEmpty(params.get("tid"),params.get("id"),params.get("task"),params.get("approveStatus"))){
            throw new BizException(GlobalRespCode.PARAM_MISSED);
        }
        String tbId = params.get("tid");
        String id = params.get("id");
        String taskId = params.get("task");
        String approveStatus = params.get("approveStatus");
//        Map<String, Object> oldData = flowableFormDataService.queryById(tbId,id);
//        String taskStatus = CommonUtil.emptyIfNull(oldData.get("_castle_approve_status"));
//        String approveUser = CommonUtil.emptyIfNull(oldData.get("_castle_approve_user"));
        Task task = taskService.createTaskQuery().taskId(taskId).includeProcessVariables().singleResult();
        Map<String,Object> variables=task.getProcessVariables();
        Map<String, Object> oldData = variables.containsKey("_fortress_form_data_map")?((Map<String, Object>)variables.get("_fortress_form_data_map")):new HashMap<>();;
        String taskStatus = CommonUtil.emptyIfNull(oldData.get("_castle_approve_status"));
        String approveUser = CommonUtil.emptyIfNull(oldData.get("_castle_approve_user"));
        if (task == null) {
            throw new BizException(BizErrorCode.TASK_ID_ERROR);
        }
//        taskService.setAssignee(taskId,user.getId()+"");
        //更新记录状态
        if(isLastOne(task)){
            if(YesNoEnum.YES.getCode().toString().equals(approveStatus)){
                taskStatus = ApproveStatusEnum.FINISH.getCode().toString();
            }else{
                taskStatus = ApproveStatusEnum.UNAPPROVED.getCode().toString();
            }
        }else{
            if(ApproveStatusEnum.PENDING.getCode().toString().equals(taskStatus)){
                taskStatus= ApproveStatusEnum.APPROVED.getCode().toString();
            }
        }
        //更新记录状态
        flowableFormDataService.updateApproveStatus(tbId,id,taskStatus);
        Integer nrOfCompletedInstances= variables.get("_castle_temp_"+task.getTaskDefinitionKey()+"_nrOfCompletedInstances")==null?0:Integer.parseInt(variables.get("_castle_temp_"+task.getTaskDefinitionKey()+"_nrOfCompletedInstances").toString());
        oldData.put("_castle_approve_status",taskStatus);
        variables.put("_castle_temp_"+task.getTaskDefinitionKey()+"_nrOfCompletedInstances",++nrOfCompletedInstances);
        variables.put("_fortress_form_data_map",oldData);
        variables.put("_castle_approve_status",taskStatus);
        //当前审批人指定抄送人
        if("01".equals(params.get("csType"))&&StrUtil.isNotEmpty(params.get("csAppointValue"))){
            variables.put(params.get("csAppointName"),params.get("csAppointValue"));
        }
        variables.put("approveStatus",approveStatus);
        Comment comment =taskService.addComment(taskId, task.getProcessInstanceId(), approveStatus, params.get("approveOpinion"));
        comment.setUserId(user.getId()+"");
        taskService.saveComment(comment);
        if(params.get("image")!=null || params.get("file")!=null){
            FlowableCommentExtendEntity commentExtendEntity = new FlowableCommentExtendEntity();
            commentExtendEntity.setTaskId(taskId);
            commentExtendEntity.setImages(params.get("image"));
            commentExtendEntity.setFiles(params.get("file"));
            commentExtendEntity.setCommId(comment.getId());
            commentExtendEntity.setPid(task.getProcessInstanceId());
            commentExtendEntity.setTid(params.get("tid"));
            commentExtendEntity.setDid(params.get("id"));
            flowableCommentExtendService.save(commentExtendEntity);
        }
        //任务处理人待定
        if (DelegationState.PENDING.equals(task.getDelegationState())) {
            taskService.resolveTask(taskId, variables);
        //任务审批
        } else {
            taskService.complete(taskId, variables);
        }
//        //流程ID
//        String pid = task.getProcessInstanceId();
//        ProcessInstance p =runtimeService.createProcessInstanceQuery().processInstanceId(pid).singleResult();
//        //流程结束
//        if(ApproveStatusEnum.APPROVED.getCode().toString().equals(taskStatus)&&(p==null||p.isEnded())){
//
//            flowableFormDataService.updateApproveStatus(tbId,id,taskStatus);
//        }
        return "完成审批";
    }

    @Override
    public List<Map<String, Object>> historyNodes(SysUser user,Map<String,String> params) {
        List<Map<String, Object>> hisFlowList = new ArrayList<>();
        String processId = params.get("pid");
        if (StringUtils.isNotBlank(processId)) {
            List<HistoricActivityInstance> list = historyService
                    .createHistoricActivityInstanceQuery()
                    .processInstanceId(processId)
                    .orderByHistoricActivityInstanceStartTime()
                    .desc().list();

            for (HistoricActivityInstance histIns : list) {
                String type = histIns.getActivityType();
                if("startEvent".equals(type)){
                    HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().includeProcessVariables().processInstanceId(histIns.getProcessInstanceId()).singleResult();
                    Map<String, Object> m = new HashMap<>();
                    m.put("taskName","发起人");
                    m.put("createTime",DateUtil.formatDateTime(histIns.getStartTime()));
                    String uid = CommonUtil.emptyIfNull(processInstance.getProcessVariables().get("_castle_flowable_start_userid"));
                    if("-1".equals(uid)){
                        m.put("userId","-1");
                        m.put("userName","超管");
                    }else{
                        SysUser sysUser = sysUserService.getByIdExtends(Long.parseLong(uid));
                        m.put("userId",sysUser.getId());
                        m.put("userName",sysUser.getRealName());
                    }
                    hisFlowList.add(m);
                }
                if ("userTask".equals(type)&&StringUtils.isNotBlank(histIns.getTaskId())) {
                    Map<String, Object> m = new HashMap<>();
                    m.put("taskId",histIns.getTaskId());
                    m.put("processId",processId);
                    m.put("taskName",histIns.getActivityName());
                    m.put("createTime",DateUtil.formatDateTime(histIns.getStartTime()));
                    m.put("endTime",histIns.getEndTime()==null?"":DateUtil.formatDateTime(histIns.getEndTime()));
                    if (StringUtils.isNotBlank(histIns.getAssignee())) {
                        if("-1".equals(histIns.getAssignee())) {
                            m.put("userId", "-1");
                            m.put("userName", "超管");
                        }else if("-10000".equals(histIns.getAssignee())){
                                m.put("userId","-10000");
                                m.put("userName","自动审批");
                        }else{
                            SysUser sysUser = sysUserService.getByIdExtends(Long.parseLong(histIns.getAssignee()));
                            m.put("userId",sysUser.getId());
                            m.put("userName",sysUser.getRealName());
                        }
                    }
                    // 展示审批人员
                    List<HistoricIdentityLink> linksForTask = historyService.getHistoricIdentityLinksForTask(histIns.getTaskId());
                    StringBuilder stringBuilder = new StringBuilder();
                    for (HistoricIdentityLink identityLink : linksForTask) {
                        // 获选人,候选组/角色(多个)
                        if ("candidate".equals(identityLink.getType())) {
//                            if (StringUtils.isNotBlank(identityLink.getUserId())) {
//                                SysUser sysUser = sysUserService.selectUserById(Long.parseLong(identityLink.getUserId()));
//                                stringBuilder.append(sysUser.getNickName()).append(",");
//                            }
                        }
                        if("participant".equals(identityLink.getType())){
                            m.put("approveUser",identityLink.getUserId());
                        }
                    }
                    // 获取意见评论内容
                    if(histIns.getEndTime()==null){
                        m.put("approveStatus","未审批");
                    }else{
                        List<Comment> commentList = taskService.getProcessInstanceComments(histIns.getProcessInstanceId());
                        commentList.forEach(comment -> {
                            if (histIns.getTaskId().equals(comment.getTaskId())) {
                                m.put("approveStatus",YesNoEnum.YES.getCode().toString().equals(comment.getType())?"通过":"驳回");
                                m.put("approveOpinion",comment.getFullMessage());
                            }
                        });
                    }
                    hisFlowList.add(m);
                }
            }
        }
        return hisFlowList;
    }

    @Override
    public IPage<Map<String, Object>> finishTasks(Page<FlowableTemplateDto> page, SysUser user, Map<String, String> params) {
        List<Map<String,Object>> list = new ArrayList<>();
        HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery().includeProcessVariables();
        //非超管只能查看自己参与的 且 自己不是发起人
        if(!user.getIsAdmin()&&!user.getIsSuperAdmin()){
            query.involvedUser(user.getId()+"")
                    .variableValueNotEquals("_castle_flowable_start_userid",user.getId()+"");
            //剔除待审批的节点
            query.variableNotExists(user.getId()+"");
        }
        if(params!=null){
            if(StrUtil.isNotEmpty(params.get("appName"))){
                query.processDefinitionName(params.get("appName"));
            }
            if(StrUtil.isNotEmpty(params.get("startTime"))){
                Date d =DateUtil.parseDate(params.get("startTime"));
                query.startedAfter(d);
            }
            if(StrUtil.isNotEmpty(params.get("endTime"))){
                query.startedBefore(DateUtil.parseDate(params.get("endTime")));
            }
        }
        query.orderByProcessInstanceStartTime().desc();
        long total = query.count();
        Page<Map<String, Object>> pageDto = new Page(page.getCurrent(), page.getSize(),total);
        Map<String,Integer> pageMap = getPageParam(page,(int)total);
        List<HistoricProcessInstance> processInstances = query.listPage(pageMap.get("start"),pageMap.get("end"));
        for(HistoricProcessInstance p:processInstances){
//            //非超管只能查看未完成中自己已审批的或者已完成的
//            if(!user.getIsAdmin()&&!user.getIsSuperAdmin()&&p.getEndTime()==null){
//                //剔除待审批的
//                List<Task> tasks = taskService.createTaskQuery().processInstanceId(p.getId()).taskAssignee(user.getId()+"").list();
//                if(tasks==null || tasks.size()==0){
//                    continue;
//                }
////                boolean flag = true;
////                for(Task t:tasks){
////                    if(t.getProcessInstanceId().equals(p.getId())){
////                        flag = false;
////                        break;
////                    }
////                }
////                if(!flag){
////                    continue;
////                }
//            }
            Map<String,Object> m = new HashMap<>();
            m.put("processId",p.getId());
            m.put("deployId",p.getDeploymentId());
            m.put("appName",p.getProcessVariables().get("_castle_flowable_app_title"));
            m.put("actKey",p.getProcessDefinitionKey());
            m.put("createTime", DateUtil.formatDateTime(p.getStartTime()));
//            Map<String, Object> oldData = flowableFormDataService.queryById(p.getProcessVariables().get("tid").toString(),p.getProcessVariables().get("id").toString());
            Map<String, Object> oldData = p.getProcessVariables().containsKey("_fortress_form_data_map")?((Map<String, Object>)p.getProcessVariables().get("_fortress_form_data_map")):new HashMap<>();
            m.put("status",oldData.get("_castle_approve_status"));
            m.put("_castle_process_engine_version",oldData.get("_castle_process_engine_version"));
            String uid = CommonUtil.emptyIfNull(p.getProcessVariables().get("_castle_flowable_start_userid"));
            if("-1".equals(uid)){
                m.put("applyUserId","-1");
                m.put("applyUserName","超管");
            }else{
                SysUser sysUser = sysUserService.getByIdExtends(Long.parseLong(uid));
                if(sysUser == null){
                    m.put("applyUserId","");
                    m.put("applyUserName","");
                }else{
                    m.put("applyUserId",sysUser.getId());
                    m.put("applyUserName",sysUser.getRealName());
                }
            }
            m.put("applyUserId",p.getStartUserId());
            m.put("applyTime",DateUtil.formatDateTime(p.getStartTime()));
            m.put("dataId",p.getProcessVariables().get("id"));
            m.put("tid",p.getProcessVariables().get("tid"));
            list.add(m);
        }
        pageDto.setRecords(list);
        return pageDto;
    }

    @Override
    public List<Map<String, Object>> allParticipants(SysUser user, Map<String, String> params) {
        List<Map<String, Object>> result = new ArrayList<>();
        //fid必须要传入流程模板ID、表单id
        if(params==null||(StrUtil.isEmpty(params.get("fid"))&&StrUtil.isEmpty(params.get("actKey")))){
            throw new BizException(GlobalRespCode.PARAM_MISSED);
        }
        //流程模板ID
        String fid = params.get("fid");
        String actKeyParam = params.get("actKey");
        FlowableTemplateEntity templateEntity=null;
        if(StrUtil.isNotEmpty(fid)){
            templateEntity = flowableTemplateService.getByIdIgnoreDel(fid);
        }else if(StrUtil.isNotEmpty(actKeyParam)){
            FlowableTemplateDto temp = new FlowableTemplateDto();
            temp.setActKey(actKeyParam);
            temp.setStatus(YesNoEnum.YES.getCode());
            List<FlowableTemplateDto> l= flowableTemplateService.listFlowableTemplateIgnoreDel(temp);
            if(l!=null&&l.size()==1){
                templateEntity =ConvertUtil.transformObj(l.get(0),FlowableTemplateEntity.class);
            }
        }
        if(templateEntity==null||YesNoEnum.NO.getCode().equals(templateEntity.getStatus())||StrUtil.isEmpty(templateEntity.getActKey()) ){
            throw new BizException(BizErrorCode.FLOWABLE_CONFIG_ERROR);
        }
        //流程示例ID
        String processId = params.get("pid");
        String engineVersion = params.get("engineVersion");
        //流程参数表
        Map<String, Object> variables = new HashMap<>();
        List<HistoricActivityInstance> activityInstances = null;
        HistoricProcessInstance hisProcess = null;
        int activeInsIndex = -1;
        //流程已启动
        if(StrUtil.isNotEmpty(processId)){
            activeInsIndex = 0;
            activityInstances = historyService.createHistoricActivityInstanceQuery().processInstanceId(processId).orderByHistoricActivityInstanceStartTime().asc().list();
            hisProcess = historyService.createHistoricProcessInstanceQuery().processInstanceId(processId).includeProcessVariables().singleResult();
            variables = hisProcess.getProcessVariables();
        //发起流程数据
        }else{
            FormDataDto formDataDto = new FormDataDto();
            formDataDto.setTbId(templateEntity.getFormKey()+"");
            initFlowableVariables(user, variables, formDataDto);
        }
        //获取流程中所有人员的信息
        Set<Long> userIds = new HashSet<>();
        String actKey = templateEntity.getActKey();
        ProcessDefinition processDefinition =null;
        if(hisProcess!=null){
            processDefinition=repositoryService.createProcessDefinitionQuery().processDefinitionId(hisProcess.getProcessDefinitionId()).singleResult();
        }else{
            if(StrUtil.isEmpty(engineVersion)){
                processDefinition=repositoryService.createProcessDefinitionQuery().processDefinitionKey(actKey).latestVersion().singleResult();
            }else{
                processDefinition=repositoryService.createProcessDefinitionQuery().processDefinitionKey(actKey).processDefinitionVersion(Integer.parseInt(engineVersion)).singleResult();
            }
        }
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
        List<FlowElement> flowElements = (List<FlowElement>)bpmnModel.getMainProcess().getFlowElements();
        //发起流程时需判断是否是分支流程
        if(hisProcess==null){
            for(FlowElement element:flowElements){
                if(element instanceof ExclusiveGateway){
                    throw new BizException(BizErrorCode.UNSTART_PROCESS_SHOW_ERROR);
                }
            }
        //初始化流程分支的数据
        }else{
            flowElements = calculateExclusiveFlow(flowElements,variables);
        }
        Map<String,Map<String, Object>> modelMap = new HashMap<>();
        List<String> nodeList= new ArrayList<>();
        for(FlowElement element:flowElements){
            Map<String, List<ExtensionAttribute>> attrs=element.getAttributes();
            Map<String, Object> map = new HashMap<>();
            //初始化任务开始时间
            if(activeInsIndex > -1 && (element instanceof UserTask || element instanceof ServiceTask)){
                for(int j = activeInsIndex;j<activityInstances.size();j++){
                    if(activityInstances.get(j).getActivityId().equals(element.getId())){
                        map.put("startDate",activityInstances.get(j).getStartTime());
                        activeInsIndex=j;
                        break;
                    }
                }
            }
            //用户节点
            if(element instanceof UserTask){
                UserTask ut = (UserTask)element;
                map.put("nodeId",ut.getId());
                map.put("nodeName",ut.getName());
                map.put("nodeTypeName","SP");
                //获取节点类型
                String userType="";
                if(attrs.get("fortress_userType")!=null){
                    List<ExtensionAttribute> eaList = attrs.get("fortress_userType");
                    ExtensionAttribute ea=eaList.get(0);
                    userType = ea.getValue();
                }
                //后台指定多个审批人
                if("assigns".equals(userType)){
                    initParticipantsList(map,userType,ut,variables,userIds);
                //指定人自己
                }else if("self".equals(userType)){
                    map.put("nodeDesc","发起人自己");
                    //nodeUserType 00 单人;01 人员列表 ;02 人员分组列表
                    map.put("nodeUserType","00");
                    Long approveUserId= Long.parseLong(variables.get("_fortress_assignees_self").toString());
                    ApproveUserDto userDto = new ApproveUserDto();
                    userDto.setId(approveUserId);
                    userDto.setStartDate(map.get("startDate")==null?null:(Date)map.get("startDate"));
                    userIds.add(approveUserId);
                    map.put("user",userDto);
                //指定多个
                }else if("users".equals(userType)){
                    initParticipantsList(map,userType,ut,variables,userIds);
                //指定一个
                }else if("single".equals(userType)){
                    map.put("nodeDesc","指定一个审批人");
                    //nodeUserType 00 单人;01 人员列表 ;02 人员分组列表
                    map.put("nodeUserType","00");
                    map.put("approveUserType","SelfAppoint");
                    map.put("approveAppointVar","_fortress_self_assignee_single_"+ut.getId());
                    String assign = FlowableUtils.getParamExpressName(ut.getAssignee());
                    Long approveUserId= Long.parseLong(variables.get(assign).toString());
                    ApproveUserDto userDto = new ApproveUserDto();
                    userDto.setId(approveUserId);
                    userDto.setStartDate(map.get("startDate")==null?null:(Date)map.get("startDate"));
                    userIds.add(approveUserId);
                    map.put("user",userDto);
                //连续多级主管
                }else if("leaders".equals(userType)){
                    map.put("nodeDesc","连续多级主管");
                    //nodeUserType 00 单人;01 人员列表 ;02 人员分组列表
                    map.put("nodeUserType","02");
                    MultiInstanceLoopCharacteristics loopCharacteristics = ut.getLoopCharacteristics();
                    String collectionName = FlowableUtils.getParamExpressName(loopCharacteristics.getInputDataItem());
                    Integer leaderLevel=Integer.parseInt(variables.get(collectionName+"_loopEnd").toString());
                    List<List<ApproveUserDto>> approveUserGroup = new ArrayList<>();
                    for(int i=1;i<=leaderLevel;i++){
                        List<String> list = (List<String>)variables.get(collectionName+"_"+i);
                        List<ApproveUserDto> approveUserDtos = new ArrayList<>();
                        for(String s:list){
                            ApproveUserDto userDto = new ApproveUserDto();
                            userDto.setId(Long.parseLong(s));
                            userDto.setStartDate(map.get("startDate")==null?null:(Date)map.get("startDate"));
                            userIds.add(Long.parseLong(s));
                            approveUserDtos.add(userDto);
                        }
                        approveUserGroup.add(approveUserDtos);
                    }
                    map.put("userGroup",approveUserGroup);
                //指定主管
                }else if("leader".equals(userType)){
                    initParticipantsList(map,userType,ut,variables,userIds);
                //角色
                }else if("roles".equals(userType)){
                    initParticipantsList(map,userType,ut,variables,userIds);
                //指定审批人
                }else if("assign".equals(userType)){
                    map.put("nodeDesc","指定审批人");
                    //nodeUserType 00 单人;01 人员列表 ;02 人员分组列表
                    map.put("nodeUserType","00");
                    ApproveUserDto userDto = new ApproveUserDto();
                    userDto.setId(Long.parseLong(ut.getAssignee()));
                    userDto.setStartDate(map.get("startDate")==null?null:(Date)map.get("startDate"));
                    userIds.add(Long.parseLong(ut.getAssignee()));
                    map.put("user",userDto);
                //程序动态创建节点(委派多人)
                }else{
                    if(variables!=null){
                        String dynamicType=variables.get("_dynamic_type_"+ut.getId())==null?"":variables.get("_dynamic_type_"+ut.getId()).toString();
                        if("delegateUsers".equals(dynamicType)){
                            initParticipantsList(map,dynamicType,ut,variables,userIds);
                        }else if("delegateUser".equals(dynamicType)){
                            map.put("nodeDesc","委派单人");
                            //nodeUserType 00 单人;01 人员列表 ;02 人员分组列表
                            map.put("nodeUserType","00");
                            ApproveUserDto userDto = new ApproveUserDto();
                            userDto.setId(Long.parseLong(ut.getAssignee()));
                            userDto.setStartDate(map.get("startDate")==null?null:(Date)map.get("startDate"));
                            userIds.add(Long.parseLong(ut.getAssignee()));
                            map.put("user",userDto);
                        }
                    }
                }
                MultiInstanceLoopCharacteristics loopCharacteristics = ut.getLoopCharacteristics();
                if(loopCharacteristics!=null){
                    String approveType="";
                    //会签
                    if("${nrOfCompletedInstances == nrOfInstances }".equals(loopCharacteristics.getCompletionCondition())){
                        approveType="会签";
                    }else{
                        approveType="或签";
                    }
                    if("会签".equals(approveType)){
                        if(loopCharacteristics.isSequential()){
                            approveType+="(按顺序审批)";
                        }else{
                            approveType+="(可同时审批)";
                        }
                    }
                    map.put("approveType",approveType);
                }
            //服务节点
            }else if(element instanceof ServiceTask){
                map.put("nodeTypeName","CS");
                ServiceTask st = (ServiceTask)element;
                map.put("nodeId",st.getId());
                //抄送服务
                if("${fortressRecipientsDelegate}".equals(st.getImplementation())){
                    map.put("nodeName",st.getName());
                    map.put("nodeUserType","01");
                    map.put("nodeDesc","抄送");
                    List<ApproveUserDto> approveUserDtos = new ArrayList<>();
                    List<FieldExtension> fieldExtensions =st.getFieldExtensions();
                    //流程预设的抄送人员
                    for(FieldExtension field:fieldExtensions){
                        if("users".equals(field.getFieldName())){
                            String[] receivers = field.getStringValue().split(",");
                            for(String receiverId:receivers){
                                ApproveUserDto userDto = new ApproveUserDto();
                                userDto.setId(Long.parseLong(receiverId));
                                userDto.setStartDate(map.get("startDate")==null?null:(Date)map.get("startDate"));
                                userIds.add(Long.parseLong(receiverId));
                                approveUserDtos.add(userDto);
                            }
                            break;
                        }
                    }
                    //发起人指定的抄送人员
                    if(variables.get(st.getId())!=null && StrUtil.isNotEmpty(variables.get(st.getId()).toString())){
                        String[] selfAppoint =variables.get(st.getId()).toString().split(",");
                        for(String receiverId:selfAppoint){
                            ApproveUserDto userDto = new ApproveUserDto();
                            userDto.setId(Long.parseLong(receiverId));
                            userDto.setStartDate(map.get("startDate")==null?null:(Date)map.get("startDate"));
                            userIds.add(Long.parseLong(receiverId));
                            approveUserDtos.add(userDto);
                        }
                    }
                    //审批节点指定的抄送人员
                    if(variables.get(st.getId()+"_cs")!=null && StrUtil.isNotEmpty(variables.get(st.getId()+"_cs").toString())){
                        if(!"nobody".equals(variables.get(st.getId()+"_cs").toString())){
                            String[] spAppoint =variables.get(st.getId()+"_cs").toString().split(",");
                            for(String receiverId:spAppoint){
                                ApproveUserDto userDto = new ApproveUserDto();
                                userDto.setId(Long.parseLong(receiverId));
                                userDto.setStartDate(map.get("startDate")==null?null:(Date)map.get("startDate"));
                                userIds.add(Long.parseLong(receiverId));
                                approveUserDtos.add(userDto);
                            }
                        }
                    }
                    map.put("users",approveUserDtos);
                }
            }
            if(!map.isEmpty()){
                nodeList.add(element.getId());
                modelMap.put(element.getId(),map);
            }
        }
        //获取已完成的节点列表
        if(StrUtil.isNotEmpty(processId)){
            //默认倒序
            List<Comment> commentList = taskService.getProcessInstanceComments(processId);
            Map<String,FlowableCommentExtendEntity> commentExtendEntityMap = flowableCommentExtendService.selToMap(processId);
            //获取审批人的审批状态、意见、审批时间
            findElementStatus(modelMap,activityInstances,commentList,result,commentExtendEntityMap);
        }
        if(!result.isEmpty()){
            boolean flag=false;
            HistoricActivityInstance instance = activityInstances.get(activityInstances.size()-1);
            String resultLastNodeId= result.get(result.size()-1).get("nodeId").toString();
            if(!instance.getActivityType().equals("endEvent") && !instance.getActivityId().equals(nodeList.get(nodeList.size()-1))){
                for(String node:nodeList){
                    if(instance.getActivityId().equals(node)){
                        flag=true;
                        if(!instance.getActivityId().equals(resultLastNodeId)){
                            result.add(modelMap.get(node));
                        }
                        continue;
                    }
                    if(flag){
                        result.add(modelMap.get(node));
                    }
                }
            }
            flag = false;
            Map<String,Object> commLastNode = result.get(result.size()-1);
            for(int i=0;i<nodeList.size();i++){
                if(nodeList.get(i).equals(commLastNode.get("nodeId"))){
                    flag= true;
                    continue;
                }
                if(flag){
                    result.add(modelMap.get(nodeList.get(i)));
                }
            }
//            HistoricActivityInstance instance = activityInstances.get(activityInstances.size()-1);
//            //该节点已审批但是未完成 则从下个节点添加
//            if(commLastNode.get("nodeId").equals(instance.getActivityId())){
//                boolean flag=false;
//                for(String node:nodeList){
//                    if(instance.getActivityId().equals(node)){
//                        flag=true;
//                        continue;
//                    }
//                    if(flag){
//                        result.add(modelMap.get(node));
//                    }
//                }
//                //该节点未审批 则从该节点添加
//            }else{
//                boolean flag=false;
//                for(String node:nodeList){
//                    if(commLastNode.get("nodeId").equals(node)){
//                        flag=true;
//                        continue;
//                    }
//                    if(flag){
//                        result.add(modelMap.get(node));
//                    }
//                }
//            }
        }else{
            for(String node:nodeList){
                result.add(modelMap.get(node));
            }
        }
        fillUserById(userIds,result);
        return result;
    }

    @Override
    public String cancelTask(SysUser user, Map<String, String> params) {
        //pid流程实例Id
        if(CommonUtil.verifyParamNull(params,params.get("pid"),params.get("tid"),params.get("id"))){
            throw new BizException(GlobalRespCode.PARAM_MISSED);
        }
        String tbId = params.get("tid");
        String id = params.get("id");
        String processId = params.get("pid");
        try {
            // 获取当前需撤回的流程实例
            ProcessInstance processInstance =
                    runtimeService.createProcessInstanceQuery()
                            .processInstanceId(processId)
                            .singleResult();
            if (processInstance==null) {
               throw new BizException(BizErrorCode.PROCESS_CANCEL_ERROR);
            }
            BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
            List<EndEvent> endNodes = (List<EndEvent>)bpmnModel.getMainProcess().findFlowElementsOfType(EndEvent.class, false);
            if(endNodes!=null&&endNodes.size()>0){
                // 获取当前流程最后一个节点
                String endId = endNodes.get(0).getId();
                List<Execution> executions =
                        runtimeService.createExecutionQuery().parentId(processInstance.getProcessInstanceId()).list();
                List<String> executionIds = new ArrayList<>();
                executions.forEach(execution -> executionIds.add(execution.getId()));
                changeProcessVariableStatus(executionIds.get(0),ApproveStatusEnum.CANCEL.getCode()+"");
                // 变更流程为已结束状态
                runtimeService.createChangeActivityStateBuilder()
                        .moveExecutionsToSingleActivityId(executionIds, endId).changeState();
                flowableFormDataService.updateApproveStatus(tbId,id,ApproveStatusEnum.CANCEL.getCode()+"");
            }
        } catch (Exception e) {
            throw new BizException(BizErrorCode.PROCESS_CANCEL_ERROR);
        }
        return "成功取消";
    }

    @Override
    public String endProcess(String processId,String tbId,String id,String approveStatus) {
        List<Task> task = taskService.createTaskQuery().processInstanceId(processId).list();
        if (CollectionUtils.isEmpty(task)) {
            throw new BizException(BizErrorCode.PROCESS_ENDED_ERROR);
        }
        try {
            // 获取当前需撤回的流程实例
            ProcessInstance processInstance =
                    runtimeService.createProcessInstanceQuery()
                            .processInstanceId(processId)
                            .singleResult();
            BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
            List<EndEvent> endNodes = (List<EndEvent>)bpmnModel.getMainProcess().findFlowElementsOfType(EndEvent.class, false);
            if(endNodes!=null&&endNodes.size()>0){
                // 获取当前流程最后一个节点
                String endId = endNodes.get(0).getId();
                List<Execution> executions =
                        runtimeService.createExecutionQuery().parentId(processId).list();
                List<String> executionIds = new ArrayList<>();
                executions.forEach(execution -> executionIds.add(execution.getId()));
                if(!CommonUtil.verifyParamEmpty(approveStatus)){
                    changeProcessVariableStatus(executionIds.get(0),approveStatus);
                    //记录状态修改为已驳回
                    flowableFormDataService.updateApproveStatus(tbId,id,approveStatus);
                }else{
                    changeProcessVariableStatus(executionIds.get(0),ApproveStatusEnum.ENDPRO.getCode()+"");
                    //记录状态修改为已驳回
                    flowableFormDataService.updateApproveStatus(tbId,id,ApproveStatusEnum.ENDPRO.getCode()+"");
                }
                // 变更流程为已结束状态
                runtimeService.createChangeActivityStateBuilder().processInstanceId(processId)
                        .moveExecutionsToSingleActivityId(executionIds, endId).changeState();

            }
        } catch (Exception e) {
            throw new BizException(BizErrorCode.PROCESS_ENDED_ERROR);
        }
        return "成功结束流程";
    }

    /**
     * 回退上个审批节点 无可退节点则结束流程
     * @param processId
     * @param taskKey
     * @param executionId
     * @param tbId
     * @param id
     * @return
     */
    @Override
    public String backToPreUserTask(String processId, String taskKey, String executionId,String tbId,String id) {
        List<Task> task = taskService.createTaskQuery().processInstanceId(processId).list();
        if (CollectionUtils.isEmpty(task)) {
            throw new BizException(BizErrorCode.PROCESS_BACK_ERROR);
        }
        try {
            // 获取当前需撤回的流程实例
            ProcessInstance processInstance =
                    runtimeService.createProcessInstanceQuery()
                            .processInstanceId(processId)
                            .includeProcessVariables()
                            .singleResult();
            processInstance.getActivityId();
            BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
            Map<String, Object> variables = processInstance.getProcessVariables();
            List<FlowElement> flowElements = (List<FlowElement>)bpmnModel.getMainProcess().getFlowElements();
            flowElements = calculateExclusiveFlow(flowElements,variables);
            List<UserTask> userTask = new ArrayList<>();
            for(FlowElement ele:flowElements){
                if(ele instanceof UserTask){
                    userTask.add((UserTask)ele);
                }
            }
//            List<UserTask> userTask = (List<UserTask>)bpmnModel.getMainProcess().findFlowElementsOfType(UserTask.class, false);
            if(userTask!=null&&userTask.size()>0){
                Integer preIndex=0;
                for(int i=0;i<userTask.size();i++){
                    UserTask ut = userTask.get(i);
                    if(ut.getId().equals(taskKey)){
                        preIndex= (i-1);
                        break;
                    }
                }
                if(preIndex>=0){
                    UserTask preNode = userTask.get(preIndex);
                    // 将流程切换到上个节点
                    runtimeService.createChangeActivityStateBuilder()
                            .moveExecutionToActivityId(executionId, preNode.getId()).changeState();
                    //将任务参数中的审批状态修改为审批中
                    Map<String, Object> oldData = variables.containsKey("_fortress_form_data_map")?((Map<String, Object>)variables.get("_fortress_form_data_map")):new HashMap<>();;
                    String taskStatus = CommonUtil.emptyIfNull(oldData.get("_castle_approve_status"));
                    if(!ApproveStatusEnum.APPROVED.getCode().toString().equals(taskStatus)){
                        changeProcessVariableStatus(executionId,ApproveStatusEnum.APPROVED.getCode()+"");
                        //状态切换为审核中
                        flowableFormDataService.updateApproveStatus(tbId,id,ApproveStatusEnum.APPROVED.getCode()+"");
                    }
                //无可回退的节点则结束流程
                }else{
                    endProcess(processId,tbId,id,ApproveStatusEnum.UNAPPROVED.getCode()+"");
                }
            }
        } catch (Exception e) {
            throw new BizException(BizErrorCode.PROCESS_BACK_ERROR);
        }
        return "成功回退流程";
    }

    /**
     * 初始化流程变量
     * @param user
     * @param variables
     * @param formDataDto
     */
    @Override
    public void initFlowableVariables(SysUser user, Map<String, Object> variables, FormDataDto formDataDto) {
        Map<String,List<String>> leadersId = sysUserService.leadersId(user);
        //表ID
        String tid = formDataDto.getTbId();
        Map<String,String> params = formDataDto.getParams();
        FlowableTemplateDto flowableTemplateDto = new FlowableTemplateDto();
        flowableTemplateDto.setFormKey(Long.parseLong(tid));
        flowableTemplateDto.setStatus(YesNoEnum.YES.getCode());
        List<FlowableTemplateDto> templates =  flowableTemplateService.listFlowableTemplate(flowableTemplateDto);
        if(templates==null || templates.size()!= 1){
            throw new BizException(BizErrorCode.FLOWABLE_CONFIG_ERROR);
        }
        FlowableTemplateDto templateDto = templates.get(0);
        String actKey = templateDto.getActKey();
        FlowableAppDto flowableAppDto = new FlowableAppDto();
        flowableAppDto.setFlowId(templateDto.getId());
        flowableAppDto.setStatus(YesNoEnum.YES.getCode());
        List<FlowableAppDto> flowableAppDtos = flowableAppService.listFlowableApp(flowableAppDto);
        if(flowableAppDtos==null || flowableAppDtos.size()!= 1){
            throw new BizException(BizErrorCode.FLOWABLE_CONFIG_ERROR);
        }
        variables.put("_castle_flowable_ack_key",actKey);
        variables.put("_castle_flowable_app_title",flowableAppDtos.get(0).getTitle());
        ProcessDefinition processDefinition =repositoryService.createProcessDefinitionQuery().processDefinitionKey(actKey).latestVersion().singleResult();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
        List<UserTask> userTask = (List<UserTask>)bpmnModel.getMainProcess().findFlowElementsOfType(UserTask.class, false);
        for(UserTask ut:userTask){
            Map<String, List<ExtensionAttribute>> attrs=ut.getAttributes();
            String userType="";
            if(attrs.get("fortress_userType")!=null){
                List<ExtensionAttribute> eaList = attrs.get("fortress_userType");
                ExtensionAttribute ea=eaList.get(0);
                userType = ea.getValue();
            }
            //后台指定多个审批人
            if("assigns".equals(userType)){
                MultiInstanceLoopCharacteristics loopCharacteristics = ut.getLoopCharacteristics();
                String collectionName = FlowableUtils.getParamExpressName(loopCharacteristics.getInputDataItem());
                if(attrs.get("fortress_users")!=null){
                    List<ExtensionAttribute> eaList = attrs.get("fortress_users");
                    ExtensionAttribute ea=eaList.get(0);
                    String assignsUser = ea.getValue();
                    List<String> list = new ArrayList<>();
                    if(StrUtil.isEmpty(assignsUser)){
                        list.add("-10000");
                    }else{
                        for(String s:assignsUser.split(",")){
                            list.add(s);
                        }
                    }
                    variables.put(collectionName,list);
                }
            //指定人自己
            }else if("self".equals(userType)){
                //发起人自己
                variables.put("_fortress_assignees_self",user.getId()+"");
            //指定多个
            }else if("users".equals(userType)){
                MultiInstanceLoopCharacteristics loopCharacteristics = ut.getLoopCharacteristics();
                String collectionName = FlowableUtils.getParamExpressName(loopCharacteristics.getInputDataItem());
                if(params!=null&&StrUtil.isNotEmpty(params.get(collectionName))){
                    if(params.get(collectionName).indexOf(",")!=-1){
                        String[] up=params.get(collectionName).split(",");
                        List<String> uids = new ArrayList<>();
                        for(String s:up){
                            uids.add(s);
                        }
                        variables.put(collectionName,uids);
                    }
                }else{
                    List<String> list = new ArrayList<>();
                    list.add("-10000");
                    variables.put(collectionName,list);
                }
            //指定一个
            }else if("single".equals(userType)){
                String assign = FlowableUtils.getParamExpressName(ut.getAssignee());
                if(params!=null&&StrUtil.isNotEmpty(params.get(assign))){
                    variables.put(assign,params.get(assign));
                }else{
                    variables.put(assign,"-10000");
                }
            //连续多级主管
            }else if("leaders".equals(userType)){
                String endCondition = "TOP";
                MultiInstanceLoopCharacteristics loopCharacteristics = ut.getLoopCharacteristics();
                String collectionName = FlowableUtils.getParamExpressName(loopCharacteristics.getInputDataItem());
                if(attrs.get("fortress_endCondition")!=null){
                    List<ExtensionAttribute> eaList = attrs.get("fortress_endCondition");
                    ExtensionAttribute ea=eaList.get(0);
                    endCondition = ea.getValue();
                }
                String leaderLevel="1";
                //连续到指定级
                if("LEAVE".equals(endCondition)){
                    //连续到指定级
                    if(attrs.get("fortress_leaderLevel")!=null){
                        List<ExtensionAttribute> eaList = attrs.get("fortress_leaderLevel");
                        ExtensionAttribute ea=eaList.get(0);
                        leaderLevel = StrUtil.isNotEmpty(ea.getValue())?ea.getValue():"1";
                    }
                    for(int i=1;i<=Integer.parseInt(leaderLevel);i++){
                        List<String> ids = leadersId.get(i+"");
                        if(ids==null){
                            ids = new ArrayList<>();
                        }
                        if(ids.isEmpty()){
                            ids.add("-10000");
                        }
                        variables.put(collectionName+"_"+i,ids);
                    }
                //到顶级
                }else{
                    leaderLevel=leadersId.keySet().size()+"";
                    //获取到全部上级
                    for(int i=1;i<=leadersId.keySet().size();i++){
                        List<String> ids = leadersId.get(i+"");
                        if(ids==null){
                            ids = new ArrayList<>();
                        }
                        if(ids.isEmpty()){
                            ids.add("-10000");
                        }
                        variables.put(collectionName+"_"+i,ids);
                    }
                }
                //默认第一层
                variables.put(collectionName,variables.get(collectionName+"_1"));
                //循环的最终节点
                variables.put(collectionName+"_loopEnd",leaderLevel);
                //当前的运行节点
                variables.put(collectionName+"_leaderIndex","1");
            //指定主管
            }else if("leader".equals(userType)){
                List<String> leaders= new ArrayList<>();
                //获取到指定级别的上级
                String leaderLevel="1";
                if(attrs.get("fortress_leaderLevel")!=null){
                    List<ExtensionAttribute> eaList = attrs.get("fortress_leaderLevel");
                    ExtensionAttribute ea=eaList.get(0);
                    leaderLevel = StrUtil.isNotEmpty(ea.getValue())?ea.getValue():"1";
                }
                //查询指定级别上级
                leaders = leadersId.get(leaderLevel);
                MultiInstanceLoopCharacteristics loopCharacteristics = ut.getLoopCharacteristics();
                String collectionName = FlowableUtils.getParamExpressName(loopCharacteristics.getInputDataItem());
                if(leaders.isEmpty()){
                    leaders.add("-10000");
                }
                variables.put(collectionName,leaders);
            //角色
            }else if("roles".equals(userType)){
                //查询角色对应的用户列表
                List<String> users= new ArrayList<>();
                List<ExtensionAttribute> roleAttrs = attrs.get("fortress_roles");
                if(roleAttrs!=null&&roleAttrs.size()>0){
                    String[] roleString=roleAttrs.get(0).getValue().split(",");
                    List<Long> roleIds = new ArrayList<>();
                    for(String r:roleString){
                        try {
                            roleIds.add(Long.parseLong(r));
                        } catch (NumberFormatException e) {
                            e.printStackTrace();
                        }
                    }
                    List<SysUserRole> urList = sysUserRoleService.queryByRoleList(roleIds);
                    for(SysUserRole ur:urList){
                        users.add(ur.getUserId()+"");
                    }
                }
                MultiInstanceLoopCharacteristics loopCharacteristics = ut.getLoopCharacteristics();
                String collectionName = FlowableUtils.getParamExpressName(loopCharacteristics.getInputDataItem());
                if(users.isEmpty()){
                    users.add("-10000");
                }
                variables.put(collectionName,users);
            }
            System.out.println("UserTask:"+ut.getName()+","+variables);
        }
        //自定义抄送人员的数据
        List<ServiceTask> serviceTasks = (List<ServiceTask>)bpmnModel.getMainProcess().findFlowElementsOfType(ServiceTask.class, false);
        for(ServiceTask st:serviceTasks){
            if(params!=null&&StrUtil.isNotEmpty(params.get(st.getId()))){
                variables.put(st.getId(),params.get(st.getId()));
            }
            List<FieldExtension> fieldExtensions = st.getFieldExtensions();
            String csType="00";
            for(FieldExtension fe:fieldExtensions){
                if("csType".equals(fe.getFieldName())){
                    csType = fe.getStringValue();
                }else if("users".equals(fe.getFieldName())){
                    variables.put(st.getId()+"_sys",fe.getStringValue());
                }
            }
            if("01".equals(csType)){
                variables.put(st.getId()+"_cs","nobody");
            }
        }
        //存入表单数据
        variables.put("_fortress_form_data_map",formDataDto.getFormData());
    }

    @Override
    public Map<String, Object> csOptional(SysUser user, Map<String, String> params) {
        Map<String, Object> result = new HashMap<>();
        result.put("csType","00");//不支持自选抄送人
        //必须要传入任务ID、表id、表记录id
        if(params==null||CommonUtil.verifyParamEmpty(params.get("taskId"),params.get("tid"),params.get("id"))){
            throw new BizException(GlobalRespCode.PARAM_MISSED);
        }
        String taskId = params.get("taskId");
        String tid = params.get("tid");
        String id = params.get("id");
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if(task == null){
            return result;
        }
        String proDefId = task.getProcessDefinitionId();
        Map<String, Object> data = flowableFormDataService.queryById(tid,id);
        if(data==null){
            return result;
        }
//        String engineVersion = data.get("_castle_process_engine_version").toString();
        ProcessDefinition processDefinition =repositoryService.createProcessDefinitionQuery().processDefinitionId(proDefId).singleResult();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());

        List<FlowElement> flowElements = (List<FlowElement>)bpmnModel.getMainProcess().getFlowElements();
        int currentIndex = -1;
        for(int i = 0;i<flowElements.size();i++){
            FlowElement fe = flowElements.get(i);
            if(task.getTaskDefinitionKey().equals(fe.getId())){
                currentIndex = i;
                break;
            }
        }
        //获取下一个节点 刨除连接线
        if(currentIndex+2<flowElements.size()){
            FlowElement fe = flowElements.get(currentIndex+2);
            if(fe instanceof ServiceTask){
                ServiceTask st = (ServiceTask)fe;
                List<FieldExtension> fieldExtensions = st.getFieldExtensions();
                String csType="00";
                for(FieldExtension field:fieldExtensions){
                    if("csType".equals(field.getFieldName())){
                        csType = field.getStringValue();
                        break;
                    }
                }
                //抄送节点为
                if("01".equals(csType)){
                    HistoricProcessInstance hisProcess = historyService.createHistoricProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).includeProcessVariables().singleResult();
                    Map<String, Object> variables = hisProcess.getProcessVariables();
                    result.put("csType","01");//支持自选抄送人
                    //系统预设的
                    for(FieldExtension field:fieldExtensions){
                        if("users".equals(field.getFieldName())){
                            //users
                            String users = field.getStringValue();
                            result.put("sysUserId",users);
                            List<SysUser> list = sysUserService.getUsersByIds(users);
                            StringBuilder names = new StringBuilder();
                            for(SysUser su:list){
                                names.append(su.getRealName()+",");
                            }
                            //用户名称
                            result.put("sysUserName",names.toString());
                            break;
                        }
                    }
                    //发起人选择的
                    if(variables.get(st.getId())!=null && StrUtil.isNotEmpty(variables.get(st.getId()).toString())){
                        result.put("initiatorAppointId",variables.get(st.getId()).toString());
                        List<SysUser> list = sysUserService.getUsersByIds(variables.get(st.getId()).toString());
                        StringBuilder names = new StringBuilder();
                        for(SysUser su:list){
                            names.append(su.getRealName()+",");
                        }
                        result.put("initiatorAppointName",names.toString());
                    }
                    result.put("thisNodeAppoint",st.getId()+"_cs");
                }
            }
        }
        return result;
    }

    @Override
    public IPage<Map<String, Object>> csToMe(Page<FlowableTemplateDto> page, SysUser user, Map<String, String> params) {
        List<Map<String,Object>> list = new ArrayList<>();
        HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery().includeProcessVariables();
        if(params!=null){
            if(StrUtil.isNotEmpty(params.get("appName"))){
                query.processDefinitionName(params.get("appName"));
            }
            if(StrUtil.isNotEmpty(params.get("startTime"))){
                Date d =DateUtil.parseDate(params.get("startTime"));
                query.startedAfter(d);
            }
            if(StrUtil.isNotEmpty(params.get("endTime"))){
                query.startedBefore(DateUtil.parseDate(params.get("endTime")));
            }
        }
        query.variableValueLike("_castle_flowable_cs_data","%"+user.getId()+"%");
        query.orderByProcessInstanceStartTime().desc();
        long total = query.count();
        Page<Map<String, Object>> pageDto = new Page(page.getCurrent(), page.getSize(),total);
        Map<String,Integer> pageMap = getPageParam(page,(int)pageDto.getTotal());
        List<HistoricProcessInstance> processInstances= query.listPage(pageMap.get("start"),pageMap.get("end"));
        for(HistoricProcessInstance p:processInstances){
            Map<String,Object> m = new HashMap<>();
            m.put("processId",p.getId());
            m.put("deployId",p.getDeploymentId());
            m.put("appName",p.getProcessVariables().get("_castle_flowable_app_title"));
            m.put("actKey",p.getProcessDefinitionKey());
            m.put("createTime", DateUtil.formatDateTime(p.getStartTime()));
//            Map<String, Object> oldData = flowableFormDataService.queryById(p.getProcessVariables().get("tid").toString(),p.getProcessVariables().get("id").toString());
            Map<String, Object> oldData = p.getProcessVariables().containsKey("_fortress_form_data_map")?((Map<String, Object>)p.getProcessVariables().get("_fortress_form_data_map")):new HashMap<>();;
            m.put("status",oldData.get("_castle_approve_status"));
            m.put("_castle_process_engine_version",oldData.get("_castle_process_engine_version"));
            String uid = CommonUtil.emptyIfNull(p.getProcessVariables().get("_castle_flowable_start_userid"));
            if("-1".equals(uid)){
                m.put("applyUserId","-1");
                m.put("applyUserName","超管");
            }else{
                SysUser sysUser = sysUserService.getByIdExtends(Long.parseLong(uid));
                m.put("applyUserId",sysUser.getId());
                m.put("applyUserName",sysUser.getRealName());
            }
            m.put("applyUserId",p.getStartUserId());
            m.put("applyTime",DateUtil.formatDateTime(p.getStartTime()));
            m.put("dataId",p.getProcessVariables().get("id"));
            m.put("tid",p.getProcessVariables().get("tid"));
            list.add(m);
        }
        pageDto.setRecords(list);
        return pageDto;
    }

    @Override
    public String delegateTask(SysUser user, Map<String, String> params) {
        if(params==null || CommonUtil.verifyParamEmpty(params.get("tid"),params.get("id"),params.get("task")
                ,params.get("delegateUsers"))){
            throw new BizException(GlobalRespCode.PARAM_MISSED);
        }
        String tbId = params.get("tid");
        String id = params.get("id");
        String taskId = params.get("task");
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (task == null) {
            throw new BizException(BizErrorCode.TASK_ID_ERROR);
        }
        String delegateUsers = params.get("delegateUsers");
        //多委派人标识
        boolean multipleFlag = false;
        if(delegateUsers.indexOf(",")!=-1){
            multipleFlag = true ;
        }
        //positionType  pre;next
        //前加签
        if(CommonUtil.verifyParamEmpty(params.get("positionType"))||"pre".equals(params.get("positionType"))){
            String newNodeId = task.getTaskDefinitionKey()+"_PRE_"+System.currentTimeMillis();
            //委派多人创建新的委派任务节点
            if(multipleFlag){
                List<String> delegateUserList = Arrays.asList(delegateUsers.split(","));
                // 00 会签 01 或签
                String delegateType = params.get("delegateType");
                DynamicUserTaskBuilder dynamicUserTaskBuilder = new DynamicUserTaskBuilder();
                dynamicUserTaskBuilder.setId(newNodeId);
                dynamicUserTaskBuilder.setName(user.getLoginName()+"委派多人");
                taskService.setVariable(taskId,"_dynamic_type_"+newNodeId,"delegateUsers");
                taskService.setVariable(taskId,"_fortress_assignees_multiple_"+newNodeId,delegateUserList);
                FortressInjectUserTaskInProcessInstanceCmd fortressInjectUserTaskInProcessInstanceCmd
                        = new FortressInjectUserTaskInProcessInstanceCmd(task.getProcessInstanceId(),dynamicUserTaskBuilder,task,"00",delegateUsers,delegateType);
                managementService.executeCommand(fortressInjectUserTaskInProcessInstanceCmd);
                //委派单人审批
            }else{
                DynamicUserTaskBuilder dynamicUserTaskBuilder = new DynamicUserTaskBuilder();
                dynamicUserTaskBuilder.setId(newNodeId);
                dynamicUserTaskBuilder.setName(user.getLoginName()+"委派");
                taskService.setVariable(taskId,"_dynamic_type_"+newNodeId,"delegateUser");
                FortressInjectSingleUserTaskInProcessInstanceCmd fortressInjectSingleUserTaskInProcessInstanceCmd
                        = new FortressInjectSingleUserTaskInProcessInstanceCmd(task.getProcessInstanceId(),dynamicUserTaskBuilder,task,"00",delegateUsers);
                managementService.executeCommand(fortressInjectSingleUserTaskInProcessInstanceCmd);
            }
            //删除任务对应的节点的相关任务信息
            List<Task> toDelTask =  taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).taskDefinitionKey(task.getTaskDefinitionKey()).list();
//        //删除任务对应的审批意见
//        taskService.deleteComments(task.getId(),task.getProcessInstanceId());
//        //删除当前任务
//        taskService.deleteTask(task.getId());
            List<String> toMoveTaskIds = new ArrayList<>();
            toDelTask.forEach(t->toMoveTaskIds.add(t.getExecutionId()));
            // 将流程切换到上个节点
            runtimeService.createChangeActivityStateBuilder()
                    .moveExecutionsToSingleActivityId(toMoveTaskIds, newNodeId).changeState();
//        for(Task t:toDelTask){
//            //删除任务对应的审批意见
//            taskService.deleteComments(t.getId(),t.getProcessInstanceId());
//            //删除当前任务
//            taskService.deleteTask(t.getId());
//        }
            Map<String, Object> oldData = flowableFormDataService.queryById(tbId,id);
            String taskStatus = CommonUtil.emptyIfNull(oldData.get("_castle_approve_status"));
            if(ApproveStatusEnum.PENDING.getCode().toString().equals(taskStatus)){
                taskStatus= ApproveStatusEnum.APPROVED.getCode().toString();
                changeProcessVariableStatus(toMoveTaskIds.get(0),taskStatus);
                //更新记录状态
                flowableFormDataService.updateApproveStatus(tbId,id,taskStatus);
            }
        //后加签
        }else{
            String newNodeId = task.getTaskDefinitionKey()+"_NEXT_"+System.currentTimeMillis();
            //委派多人创建新的委派任务节点
            if(multipleFlag){
                List<String> delegateUserList = Arrays.asList(delegateUsers.split(","));
                // 00 会签 01 或签
                String delegateType = params.get("delegateType");
                DynamicUserTaskBuilder dynamicUserTaskBuilder = new DynamicUserTaskBuilder();
                dynamicUserTaskBuilder.setId(newNodeId);
                dynamicUserTaskBuilder.setName(user.getLoginName()+"委派多人");
                taskService.setVariable(taskId,"_dynamic_type_"+newNodeId,"delegateUsers");
                taskService.setVariable(taskId,"_fortress_assignees_multiple_"+newNodeId,delegateUserList);
                FortressInjectUserTaskInProcessInstanceCmd fortressInjectUserTaskInProcessInstanceCmd
                        = new FortressInjectUserTaskInProcessInstanceCmd(task.getProcessInstanceId(),dynamicUserTaskBuilder,task,"01",delegateUsers,delegateType);
                managementService.executeCommand(fortressInjectUserTaskInProcessInstanceCmd);
                //委派单人审批
            }else{
                DynamicUserTaskBuilder dynamicUserTaskBuilder = new DynamicUserTaskBuilder();
                dynamicUserTaskBuilder.setId(newNodeId);
                dynamicUserTaskBuilder.setName(user.getLoginName()+"委派");
                taskService.setVariable(taskId,"_dynamic_type_"+newNodeId,"delegateUser");
                FortressInjectSingleUserTaskInProcessInstanceCmd fortressInjectSingleUserTaskInProcessInstanceCmd
                        = new FortressInjectSingleUserTaskInProcessInstanceCmd(task.getProcessInstanceId(),dynamicUserTaskBuilder,task,"01",delegateUsers);
                managementService.executeCommand(fortressInjectSingleUserTaskInProcessInstanceCmd);
            }
        }
        return "委派完成";
    }
    /**
     * 查询运行中任务各用户及抄送人节点状态
     * @param modelMap
     * @param activityInstances
     * @param commentList
     * @param result
     * @param commentExtendEntityMap 评论扩展信息
     */
    private void findElementStatus(Map<String,Map<String, Object>> modelMap,List<HistoricActivityInstance> activityInstances,List<Comment> commentList,List<Map<String, Object>> result,Map<String,FlowableCommentExtendEntity> commentExtendEntityMap){
        //将连续相同节点分组
        List<Map<String,List<HistoricActivityInstance>>> nodeList = new ArrayList<>();
        for(HistoricActivityInstance activityInstance:activityInstances){
            //审批节点 或 抄送节点
            if(activityInstance.getActivityType().equals("userTask")||activityInstance.getActivityType().equals("serviceTask")){
                if(nodeList.isEmpty()){
                    Map<String,List<HistoricActivityInstance>>  map = new HashMap<>();
                    List<HistoricActivityInstance> l=new ArrayList<>();
                    l.add(activityInstance);
                    map.put(activityInstance.getActivityId(),l);
                    nodeList.add(map);
                }else{
                    Map<String,List<HistoricActivityInstance>>  map = nodeList.get(nodeList.size()-1);
                    List<HistoricActivityInstance> l=map.get(activityInstance.getActivityId());
                    if(l!=null){
                        l.add(activityInstance);
                        map.put(activityInstance.getActivityId(),l);
                    }else{
                        Map<String,List<HistoricActivityInstance>>  newMap = new HashMap<>();
                        l=new ArrayList<>();
                        l.add(activityInstance);
                        newMap.put(activityInstance.getActivityId(),l);
                        nodeList.add(newMap);
                    }
                }
            }
        }
        for(int i=0;i<nodeList.size();i++){
            Map<String,List<HistoricActivityInstance>>  activeNodemap = nodeList.get(i);
            for(String key:activeNodemap.keySet()){
                Map<String, Object> dataMap = modelMap.get(key);
                if(dataMap!=null){
                    Map<String, Object> map = copyModelMap(dataMap);
                    if("SP".equals(map.get("nodeTypeName").toString())){
                        if(fillApproveInfo(commentList,activeNodemap.get(key),map,commentExtendEntityMap)){
                            result.add(map);
                        };
                    }else if("CS".equals(map.get("nodeTypeName").toString())){
                        if(map.get("nodeId").toString().equals(key)&&activeNodemap.get(key).get(0).getEndTime()!=null){
                            List<ApproveUserDto> userDtos = (List<ApproveUserDto>)map.get("users");
                            for(ApproveUserDto dto:userDtos){
                                dto.setApproveStatus("02");
                                dto.setApproveDate(activeNodemap.get(key).get(0).getEndTime());
                            }
                            result.add(map);
                        }
                    }
                }
            }
        }
    }

    /**
     * 深层复制模型map的数据
     * @param map
     * @return
     */
    private Map<String, Object> copyModelMap(Map<String, Object> map){
        Map<String, Object> newMap = new HashMap<>();
        for(String key:map.keySet()){
            newMap.put(key,map.get(key));
        }
        //解耦usr数据
        //单一审批人
        if(map.get("user")!=null){
            ApproveUserDto dto = (ApproveUserDto)map.get("user");
            newMap.put("user",copyNewDto(dto));
            //多个审批人
        }else if(map.get("users")!=null){
            List<ApproveUserDto> userDtos = (List<ApproveUserDto>)map.get("users");
            List<ApproveUserDto> userDtosNew= new ArrayList<>();
            for(ApproveUserDto dto:userDtos){
                userDtosNew.add(copyNewDto(dto));
            }
            newMap.put("users",userDtosNew);
            //连续上级
        }else if(map.get("userGroup")!=null){
            List<List<ApproveUserDto>> approveUserGroup = (List<List<ApproveUserDto>>)map.get("userGroup");
            List<List<ApproveUserDto>> approveUserGroupNew = new ArrayList<>();
            for(List<ApproveUserDto> l:approveUserGroup){
                List<ApproveUserDto> lNew = new ArrayList<>();
                for(ApproveUserDto dto:l){
                    lNew.add(copyNewDto(dto));
                }
                approveUserGroupNew.add(lNew);
            }
            newMap.put("userGroup",approveUserGroupNew);
        }
        return newMap;
    }

    /**
     * 复制新数据对象
     * @param dto
     * @return
     */
    private ApproveUserDto copyNewDto(ApproveUserDto dto){
        ApproveUserDto newDto = new ApproveUserDto();
        newDto.setId(dto.getId());
        newDto.setStartDate(dto.getStartDate());
        newDto.setOptFlag(dto.getOptFlag());
        return newDto;
    }

    /**
     * 填充审核信息
     * @param commentList
     * @param map
     */
    private boolean fillApproveInfo(List<Comment> commentList,List<HistoricActivityInstance> activityInstances,Map<String, Object> map,Map<String,FlowableCommentExtendEntity> commentExtendEntityMap){
        List<Comment> repeatList = new ArrayList<>();
        boolean isFind= false;
        //单一审批人
        if(map.get("user")!=null){
            ApproveUserDto dto = (ApproveUserDto)map.get("user");
            isFind=fillApproveInfo(commentList,activityInstances,repeatList,dto,commentExtendEntityMap);
            //多个审批人
        }else if(map.get("users")!=null){
            List<ApproveUserDto> userDtos = (List<ApproveUserDto>)map.get("users");
            for(ApproveUserDto dto:userDtos){
                isFind= fillApproveInfo(commentList,activityInstances,repeatList,dto,commentExtendEntityMap)?true:isFind;
            }
            //连续上级
        }else if(map.get("userGroup")!=null){
            List<List<ApproveUserDto>> approveUserGroup = (List<List<ApproveUserDto>>)map.get("userGroup");
            for(List<ApproveUserDto> l:approveUserGroup){
                for(ApproveUserDto dto:l){
                    isFind= fillApproveInfo(commentList,activityInstances,repeatList,dto,commentExtendEntityMap)?true:isFind;
                }
            }
        }

        return isFind;
    }

    /**
     * 填充审核信息
     * @param dto
     * 审核状态 00 待审核 01 审核中 02 通过 03 驳回 04 委派（前加签|后加签）05 转办 06 取消 07 结束
     */
    private boolean fillApproveInfo(List<Comment> commentList,List<HistoricActivityInstance> activityInstances,List<Comment> repeatList,ApproveUserDto dto,Map<String,FlowableCommentExtendEntity> commentExtendEntityMap){
        boolean isFind = false;
        for(int i=commentList.size()-1;i>=0;i--){
            Comment comment = commentList.get(i);
            for(HistoricActivityInstance activityInstance:activityInstances){
                if (activityInstance.getTaskId().equals(comment.getTaskId())&&comment.getUserId().equals(dto.getId()+"")) {
                    FlowableCommentExtendEntity commentExtendEntity = commentExtendEntityMap.get(comment.getId());
                    if(commentExtendEntity!=null){
                        dto.setCommId(comment.getId());
                        dto.setImage(commentExtendEntity.getImages());
                        dto.setFile(commentExtendEntity.getFiles());
                    }
                    if(YesNoEnum.YES.getCode().toString().equals(comment.getType())){
                        dto.setApproveStatus("02");
                    }else if(YesNoEnum.NO.getCode().toString().equals(comment.getType())){
                        dto.setApproveStatus("03");
                    }else if("04".equals(comment.getType())){
                        dto.setApproveStatus("04");
                    }
                    dto.setApproveDate(comment.getTime());
                    if(dto.getStartDate()!=null){
                        dto.setTimeConsuming(DateUtil.between(dto.getStartDate(),dto.getApproveDate(), DateUnit.SECOND));
                    }
                    dto.setApproveOpinion(comment.getFullMessage());
                    isFind=true;
                    repeatList.add(comment);
                    break;
                }
            }
            commentList.removeAll(repeatList);
            if(isFind){
                return isFind;
            }
        }
        return isFind;
    }

    /**
     * 获取分页参数
     * @param page
     * @return Map offset:偏移量 rows：记录数
     */
    private  Map<String,Integer> getPageParam(Page page,Integer total){
        Map<String,Integer> map = new HashMap<>();
        Long start = (page.getCurrent()-1)*page.getSize();
        Long end = (page.getCurrent()*page.getSize())>total?total:(page.getCurrent()*page.getSize());
        map.put("start",Integer.parseInt(start.toString()));
        map.put("end",Integer.parseInt(end.toString()));
        return map;
    }

    private void initParticipantsList(Map<String, Object> map,String userType,UserTask ut,Map<String, Object> variables,Set<Long> userIds){
        MultiInstanceLoopCharacteristics loopCharacteristics = ut.getLoopCharacteristics();
        String collectionName = FlowableUtils.getParamExpressName(loopCharacteristics.getInputDataItem());
        if("users".equals(userType)){
            map.put("nodeDesc","指定多个审批人");
            map.put("approveUserType","SelfAppoint");
            map.put("approveAppointVar",collectionName);
        }else if("leader".equals(userType)){
            map.put("nodeDesc","指定级别主管");
        }else if("roles".equals(userType)){
            map.put("nodeDesc","指定角色");
        }else if("assigns".equals(userType)){
            //后台指定多个审批人
            map.put("nodeDesc","系统指定多个审批人");
        }else if("delegateUsers".equals(userType)){
            map.put("nodeDesc","委派多人");
        }
        //nodeUserType 00 单人;01 人员列表 ;02 人员分组列表
        map.put("nodeUserType","01");

        List<String> list = (List<String>)variables.get(collectionName);
        List<ApproveUserDto> approveUserDtos = new ArrayList<>();
        for(String s:list){
            ApproveUserDto userDto = new ApproveUserDto();
            userDto.setId(Long.parseLong(s));
            userDto.setStartDate(map.get("startDate")==null?null:(Date)map.get("startDate"));
            userIds.add(Long.parseLong(s));
            approveUserDtos.add(userDto);
        }
        map.put("users",approveUserDtos);
    }

    /**
     * 依据ID填充用户信息
     * @param idScope
     * @param list
     */
    private void fillUserById(Set<Long> idScope,List<Map<String, Object>> list){
        if(idScope.isEmpty()||list.isEmpty()){
            return;
        }
        QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
        wrapper.in("id",idScope);
        List<SysUser> users = sysUserService.list(wrapper);
        Map<Long,SysUser> userMap= new HashMap<>();
        users.forEach(item->{
            userMap.put(item.getId(),item);
        });
        for(Map<String, Object> m:list){
            String nodeUserType = CommonUtil.emptyIfNull(m.get("nodeUserType"));
            //nodeUserType 00 单人;01 人员列表 ;02 人员分组列表
            if("00".equals(nodeUserType)){
                convertToApproveUser((ApproveUserDto)m.get("user"),userMap);
            }else if("01".equals(nodeUserType)){
                List<ApproveUserDto> approveUserDtos = (List<ApproveUserDto>)m.get("users");
                for(ApproveUserDto dto:approveUserDtos){
                    convertToApproveUser(dto,userMap);
                }
            }else if("02".equals(nodeUserType)){
                List<List<ApproveUserDto>> approveUserGroup = (List<List<ApproveUserDto>>)m.get("userGroup");
                for(List<ApproveUserDto> l:approveUserGroup){
                    for(ApproveUserDto a:l){
                        convertToApproveUser(a,userMap);
                    }
                }
            }
        }
    }

    /**
     * 将系统人员信息转换为审批人员信息
     * @param userDto
     * @param userMap
     */
    private void convertToApproveUser(ApproveUserDto userDto,Map<Long,SysUser> userMap){
        SysUser u = userMap.get(userDto.getId());
        if(u!=null){
            userDto.setNickname(u.getNickname());
            userDto.setLoginName(u.getLoginName());
            userDto.setPhone(u.getPhone());
            userDto.setRealName(u.getRealName());
        }
    }

    /**
     * 计算分支流程的节点列表
     * @param flowElements
     * @param variables
     * @return
     */
    private List<FlowElement> calculateExclusiveFlow(List<FlowElement> flowElements, Map<String, Object> variables) {
        if(flowElements==null || flowElements.isEmpty() || variables==null ||variables.isEmpty()){
            throw new BizException(BizErrorCode.FLOWABLE_CONFIG_ERROR);
        }
        List<FlowElement> newFlowElements = new ArrayList<>();
        FlowElement startEle = findStartEle(flowElements);
        newFlowElements.add(startEle);
        FlowElement node = findNextEle(startEle,flowElements,variables);
        while(node!=null){
            newFlowElements.add(node);
            node = findNextEle(node,flowElements,variables);
        }
        return newFlowElements;
    }

    /**
     * 获取下一个节点，有且仅有一个（分支的话依据参数判断）
     * @param ele
     * @param flowElements
     * @param variables
     * @return
     */
    private FlowElement findNextEle(FlowElement ele,List<FlowElement> flowElements,Map<String, Object> variables){
        List<FlowElement> list = findNextEles(ele,flowElements);
        if(list == null || list.isEmpty()){
            return null;
        }else if(list.size() == 1){
            return list.get(0);
        }else{
            ProcessEngineConfigurationImpl processEngineConfiguration = (ProcessEngineConfigurationImpl) processEngine.getProcessEngineConfiguration();
            ExpressionManager expressionManager = processEngineConfiguration.getExpressionManager();
            VariableContainer variableContainer = new VariableContainerWrapper(variables);
            //多个连接线 获取第一个符合条件的，如果没有符合条件的则返回第一个连接线
            for(FlowElement e:list){
                if(e instanceof SequenceFlow){
                    SequenceFlow node = (SequenceFlow) e;
                    String conditionExpression = node.getConditionExpression();
                    Expression expr = expressionManager.createExpression(conditionExpression);
                    Object result = expr.getValue(variableContainer);
                    if (result instanceof Boolean && ((Boolean) result)) {
                        return e;
                    }
                }else{
                    throw new BizException(BizErrorCode.FLOWABLE_CONFIG_ERROR);
                }
            }
            return list.get(0);
        }
    }

    /**
     * 获取当前节点的下个节点
     * （非连接线有且只有一个，连接线如果返回多个则是条件连接线）
     * @param ele
     * @param flowElements
     * @return
     */
    private List<FlowElement> findNextEles(FlowElement ele,List<FlowElement> flowElements){
        if(ele == null || flowElements == null || flowElements.isEmpty()){
            throw new BizException(BizErrorCode.FLOWABLE_CONFIG_ERROR);
        }
        List<FlowElement> list = new ArrayList<>();
        //该节点是连接线 则下个节点是功能节点
        if(ele instanceof SequenceFlow){
            SequenceFlow node = (SequenceFlow) ele;
            String nextId = node.getTargetRef();
            if(StrUtil.isEmpty(nextId)){
                throw new BizException(BizErrorCode.FLOWABLE_CONFIG_ERROR);
            }
            for(FlowElement e:flowElements){
                if(nextId.equals(e.getId())){
                    list.add(e);
                    return list;
                }
            }
            //该节点是功能节点，下个节点是连接线
        }else{
            String sourceId = ele.getId();
            for(FlowElement e:flowElements){
                if(e instanceof SequenceFlow){
                    SequenceFlow node = (SequenceFlow) e;
                    if(sourceId.equals(node.getSourceRef())){
                        list.add(e);
                    }
                }
            }
        }
        return list;
    }

    /**
     * 获取启动节点 默认有且只有一个起始节点
     * @param flowElements
     * @return
     */
    private FlowElement findStartEle(List<FlowElement> flowElements){
        for(FlowElement ele:flowElements){
            if(ele instanceof StartEvent){
                return ele;
            }
        }
        throw new BizException(BizErrorCode.FLOWABLE_CONFIG_ERROR);
    }

    @Override
    public String turnTask(SysUser user, Map<String, String> params) {
        if(params==null || CommonUtil.verifyParamEmpty(params.get("tid"),params.get("id"),params.get("task")
                ,params.get("turnUser"))){
            throw new BizException(GlobalRespCode.PARAM_MISSED);
        }
        String tbId = params.get("tid");
        String id = params.get("id");
        String taskId = params.get("task");
        String userId = params.get("turnUser");
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        Map<String,Object> nodeMap = getNodeInfo(task.getTaskDefinitionKey(),task.getProcessDefinitionId(),task.getProcessInstanceId());
        if(nodeMap!=null){
            String name = CommonUtil.emptyIfNull(nodeMap.get("name"));
            if(nodeMap.get("value")!=null){
                if(nodeMap.get("value") instanceof String){
                    taskService.setVariable(task.getId(),name,userId);
                }else if(nodeMap.get("value") instanceof List){
                    List<String> list = (List<String>)nodeMap.get("value");
                    List<String> newData = new ArrayList<>();
                    for(String s:list){
                        if(s.equals(user.getId().toString())){
                            newData.add(userId);
                        }else{
                            newData.add(s);
                        }
                    }
                    taskService.setVariable(task.getId(),name,newData);
                }
            }
        }
        taskService.setAssignee(taskId,userId);
        return "已转办";
    }

    @Override
    public List<Map<String, Object>> getAllBackNodes(SysUser user, Map<String, String> params) {
        if(params==null || CommonUtil.verifyParamEmpty(params.get("tid"),params.get("id"),params.get("task")
                ,params.get("actKey"),params.get("pid"))){
            throw new BizException(GlobalRespCode.PARAM_MISSED);
        }
        String taskId = params.get("task");
        Task taskObj = taskService.createTaskQuery().taskId(taskId).singleResult();
        if(taskObj==null){
            throw new BizException(BizErrorCode.PROCESS_BACK_ERROR);
        }
        BpmnModel bpmnModel = repositoryService.getBpmnModel(taskObj.getProcessDefinitionId());
        List<UserTask> userTasks = (List<UserTask>)bpmnModel.getMainProcess().findFlowElementsOfType(UserTask.class, false);
        List<Map<String, Object>> result = new ArrayList<>();
        for(int i=0;i<userTasks.size();i++){
            UserTask ut = userTasks.get(i);
            if(!(taskObj.getTaskDefinitionKey().equals(ut.getId()))){
                Map<String, Object> map = new HashMap<>();
                map.put("nodeId",ut.getId());
                map.put("nodeName",ut.getName());
                result.add(map);
            }else{
                break;
            }
        }
        return result;
    }

    @Override
    public String backToNode(SysUser user, Map<String, String> params) {
        if(params==null || CommonUtil.verifyParamEmpty(params.get("tid"),params.get("id"),params.get("task")
                ,params.get("actKey"),params.get("pid"),params.get("nodeId"))){
            throw new BizException(GlobalRespCode.PARAM_MISSED);
        }
        String tbId = params.get("tid");
        String id = params.get("id");
        String taskId = params.get("task");
        String actKey = params.get("actKey");
        String pid = params.get("pid");
        String nodeId = params.get("nodeId");
        Task taskObj = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (taskObj==null ) {
            throw new BizException(BizErrorCode.PROCESS_BACK_ERROR);
        }
        try {
            // 将流程切换到上个节点
            runtimeService.createChangeActivityStateBuilder()
                    .moveExecutionToActivityId(taskObj.getExecutionId(), nodeId).changeState();
        } catch (Exception e) {
            throw new BizException(BizErrorCode.PROCESS_BACK_ERROR);
        }
        return "成功回退流程";
    }

    @Override
    public String refuseBackInfo(SysUser user, Map<String, String> params) {
        if(params==null || CommonUtil.verifyParamEmpty(params.get("tid"),params.get("id"),params.get("task")
                ,params.get("actKey"),params.get("pid"))){
            throw new BizException(GlobalRespCode.PARAM_MISSED);
        }
        String tbId = params.get("tid");
        String id = params.get("id");
        String taskId = params.get("task");
        String actKey = params.get("actKey");
        String pid = params.get("pid");
        Task taskObj = taskService.createTaskQuery().taskId(taskId).singleResult();
        Map<String,Object> map = getNodeInfo(taskObj.getTaskDefinitionKey(),taskObj.getProcessDefinitionId(),pid);
        return CommonUtil.emptyIfNull(map.get("refuseType"));
    }

    /**
     * 获取指定节点的信息
     * @param nodeId 节点id
     * @param pdId 流程定义ID
     * @param pid 流程id
     * @return
     */
    private Map<String,Object> getNodeInfo(String nodeId,String pdId,String pid){
        //流程参数表
        Map<String, Object> variables = new HashMap<>();
        List<HistoricActivityInstance> activityInstances = null;
        HistoricProcessInstance hisProcess = null;
        hisProcess = historyService.createHistoricProcessInstanceQuery().processInstanceId(pid).includeProcessVariables().singleResult();
        variables = hisProcess.getProcessVariables();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(pdId);
        List<UserTask> userTasks = (List<UserTask>)bpmnModel.getMainProcess().findFlowElementsOfType(UserTask.class, false);
        Map<String,Object> resultMap = new HashMap<>();
        for(UserTask ut:userTasks){
            if(ut.getId().equals(nodeId)){
                Map<String,String> nodeMap = new HashMap<>();
                String variableName="";
                Map<String, List<ExtensionAttribute>> attrs=ut.getAttributes();
                String userType="";
                if(attrs.get("fortress_userType")!=null){
                    List<ExtensionAttribute> eaList = attrs.get("fortress_userType");
                    ExtensionAttribute ea=eaList.get(0);
                    userType = ea.getValue();
                }
                //后台指定多个审批人
                if("assigns".equals(userType)){
                    MultiInstanceLoopCharacteristics loopCharacteristics = ut.getLoopCharacteristics();
                    variableName = FlowableUtils.getParamExpressName(loopCharacteristics.getInputDataItem());
                    //指定人自己
                }else if("self".equals(userType)){
                    //发起人自己
                    variableName = "_fortress_assignees_self";
                    //指定多个
                }else if("users".equals(userType)){
                    MultiInstanceLoopCharacteristics loopCharacteristics = ut.getLoopCharacteristics();
                    variableName = FlowableUtils.getParamExpressName(loopCharacteristics.getInputDataItem());
                    //指定一个
                }else if("single".equals(userType)){
                    variableName = FlowableUtils.getParamExpressName(ut.getAssignee());
                    //连续多级主管
                }else if("leaders".equals(userType)){
                    String endCondition = "TOP";
                    MultiInstanceLoopCharacteristics loopCharacteristics = ut.getLoopCharacteristics();
                    String collectionName = FlowableUtils.getParamExpressName(loopCharacteristics.getInputDataItem());
                    String index = variables.get(collectionName+"_leaderIndex").toString();
                    variableName = collectionName+"_"+index;
                    //指定主管
                }else if("leader".equals(userType)){
                    MultiInstanceLoopCharacteristics loopCharacteristics = ut.getLoopCharacteristics();
                    variableName = FlowableUtils.getParamExpressName(loopCharacteristics.getInputDataItem());
                    //角色
                }else if("roles".equals(userType)){
                    MultiInstanceLoopCharacteristics loopCharacteristics = ut.getLoopCharacteristics();
                    variableName = FlowableUtils.getParamExpressName(loopCharacteristics.getInputDataItem());
                //程序动态创建节点(委派多人)
                }else{
                    variableName = "_dynamic_type_"+ut.getId();
                }
                resultMap.put("name",variableName);
                resultMap.put("value",variables.get(variableName));
                List<FlowableListener> listeners = ut.getTaskListeners();
                if(listeners!=null){
                    out:for(FlowableListener listener:listeners){
                        if("complete".equals(listener.getEvent())){
                            List<FieldExtension> extensions = listener.getFieldExtensions();
                            if(extensions!=null){
                                for(FieldExtension extension:extensions){
                                    if("refuseType".equals(extension.getFieldName())){
                                        resultMap.put("refuseType",extension.getStringValue());
                                        break out;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        return resultMap;
    }

    /**
     * 校验该任务是否是流程最后一个任务
     * @param task
     * @return
     */
    private boolean isLastOne(Task task){
        BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
        List<UserTask> userTask = (List<UserTask>)bpmnModel.getMainProcess().findFlowElementsOfType(UserTask.class, false);
        if(userTask!=null){
            for(int i=userTask.size()-1;i>=0;i--){
                UserTask ut = userTask.get(i);
                Map<String, List<ExtensionAttribute>> attrs=ut.getAttributes();
                //该任务节点是最后一个节点
                if(ut.getId().equals(task.getTaskDefinitionKey())){
                    //获取节点类型
                    String userType="";
                    if(attrs.get("fortress_userType")!=null){
                        List<ExtensionAttribute> eaList = attrs.get("fortress_userType");
                        ExtensionAttribute ea=eaList.get(0);
                        userType = ea.getValue();
                    }
                    Set<String> singleUserType = Stream.of("self、single、assign、delegateUser".split("、")).collect(Collectors.toSet());
                    if(singleUserType.contains(userType)){
                        return true;
                        //多人审批
                    }else{
                        String approveType="或签";
                        MultiInstanceLoopCharacteristics loopCharacteristics = ut.getLoopCharacteristics();
                        if(loopCharacteristics!=null){
                            //会签
                            if("${nrOfCompletedInstances == nrOfInstances }".equals(loopCharacteristics.getCompletionCondition())){
                                approveType="会签";
                            }
                        }
                        if("或签".equals(approveType)){
                            return true;
                        }else{
                            Map<String, Object> variables = task.getProcessVariables();
                            //已完成的实例总数
                            Integer nrOfCompletedInstances= variables.get("_castle_temp_"+task.getTaskDefinitionKey()+"_nrOfCompletedInstances")==null?0:Integer.parseInt(variables.get("_castle_temp_"+task.getTaskDefinitionKey()+"_nrOfCompletedInstances").toString());
                            //实例总数
                            Integer nrOfInstances=variables.containsKey("_fortress_assignees_multiple_"+task.getTaskDefinitionKey())?((List<String>)variables.get("_fortress_assignees_multiple_"+task.getTaskDefinitionKey())).size():1;
                            if(nrOfCompletedInstances == (nrOfInstances-1)){
                                return true;
                            }else{
                                return false;
                            }
                        }
                    }
                }else{
                    return false;
                }
            }
            return true;
        }else{
            return true;
        }
    }

    /**
     * 修改流程参数中的记录审批状态
     * @param excutionId 执行ID
     * @param castleApproveStatus 需要修改的目标状态
     */
    private void changeProcessVariableStatus(String excutionId,String castleApproveStatus){
        Map<String, Object> variables = runtimeService.getVariables(excutionId);
        //将任务参数中的审批状态修改为审批中
        Map<String, Object> oldData = variables.containsKey("_fortress_form_data_map")?((Map<String, Object>)variables.get("_fortress_form_data_map")):new HashMap<>();;
        oldData.put("_castle_approve_status",castleApproveStatus);
        variables.put("_castle_approve_status",castleApproveStatus);
        runtimeService.setVariable(excutionId,"_fortress_form_data_map",oldData);
    }


}
